#include <Arduino.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include <WiFi.h>
#include <Adafruit_AHTX0.h>
#include <ArduinoJson.h>
#include "BMP.h"
#include "font/temp_30.h"
#include <HTTPClient.h>//http连接
#include <ArduinoJson.h>//引入json
#include "font/font_18_weather.h"


#define NTP1  "ntp1.aliyun.com"
#define NTP2  "ntp2.aliyun.com"
#define NTP3  "ntp3.aliyun.com"
#define WIDTH  160
#define HEIGHT 80
#define I2C_SDA 4 //传感器I2C使用的管脚
#define I2C_SCL 5
#define Key0 8  //up
#define Key1 13 //down
#define Key2 5  //right
#define Key3 9  //left
#define Key4 4  //mid 暂时没有使用
#define REDLED 12 //WIFI开始连接，亮灯，连接成功后，灯灭
HTTPClient http;

String today_status;
int today_max;
int today_min;
String tomorrow_status;
int tomorrow_max;
int tomorrow_min;
String last_status;
int last_max;
int last_min;
String payload = "";

String UserKey = "key=059629f9abe341af8861e6f99229d979&unit=m&lang=zh&gzip=n";   // 私钥 https://dev.heweather.com/docs/start/get-api-key
String Location = "location=101220109&"; // 城市代码 https://github.com/heweather/LocationList,表中的 Location_ID
// 101190113 雨花台
String base = "https://devapi.qweather.com/v7/weather/3d?";


TFT_eSPI tft = TFT_eSPI();  // Invoke library, pins defined in User_Setup.h
TFT_eSprite spr = TFT_eSprite(&tft);
Adafruit_AHTX0 aht;
WiFiClient client;

// =========================================================================
// Setup
// =========================================================================
const char* ssid     = "tgy";    	 // WIFI账户
//const char* ssid     = "TGYiPhone";
const char* password = "wifi112358";	 // WIFI密码
//const char* password = "1234567809";	 // WIFI密码


int16_t gpu_usage;
int16_t cpu_usage;
int16_t ram_usage;
int i = 1;

char stateFlag = 0;  // 主状态机状态
char stateFlag2 = 0; // 附状态机状态
char keyFlag = 0;    // 按键状态

void KeyScan(){

    if (keyFlag == 1){
    // 检查按键是否释放
    if(digitalRead(Key0) == 0)
      return;
    else if (digitalRead(Key1) == 0)
      return;
    else if (digitalRead(Key2) == 0)
      return;
    else if (digitalRead(Key3) == 0)
      return;
    else if (digitalRead(Key4) == 0)
      return;
    else
      keyFlag = 0; //按键已经释放
  }

  else{
    if(digitalRead(Key0) == 0){
      keyFlag = 1;
      stateFlag = stateFlag + 1;
      if(stateFlag > 2)
        stateFlag = 0;
      return;
    }
    else if (digitalRead(Key1) == 0){
      keyFlag = 1;
      if(stateFlag > 0)
        stateFlag = stateFlag - 1;
        else
        stateFlag = 2;
      return;
    }
    else if (digitalRead(Key2) == 0){
      keyFlag = 1;
        if(stateFlag2 > 0)
        stateFlag2 = stateFlag2 - 1;
        else
        stateFlag2 = 2;
      return;
    }
    else if (digitalRead(Key3) == 0){
      keyFlag = 1;

      stateFlag2 = stateFlag2 + 1;
      if(stateFlag2 > 2)
        stateFlag2 = 0;
      return;
    }
    else if (digitalRead(Key4) == 0){
      stateFlag = 0;
      stateFlag2=0;
      return;
    }
  }
}

void temp_hum()
{
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data

  Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C");
  Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");

  // Draw a black rectangle in sprite so when we move it 1 pixel it does not leave a trail
  // on the black screen background
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_BLACK);
  spr.setCursor(0, 0);

  spr.fillSprite(TFT_BLACK);
  spr.setTextColor(TFT_YELLOW, TFT_BLACK);
  spr.setTextFont(2);
  spr.setTextSize(2);
  spr.setCursor(0, 8);
  spr.print("T: "); spr.print(temp.temperature,1);//默认是保留两位小数，这里我们保留一位小数
  spr.loadFont(temp_30);
  spr.setCursor(90, 12);
  spr.printf("℃");
  spr.unloadFont();
  spr.setCursor(0, 40);
  spr.print("H: "); spr.print(humidity.relative_humidity,1);spr.println("%");
  spr.pushSprite(0, 0);

}

void temp()
{
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data

  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_WHITE);
  spr.setCursor(0, 0);

  spr.fillSprite(TFT_WHITE);
  spr.setTextColor(TFT_BLACK, TFT_WHITE);
  spr.setTextFont(2);
  spr.setTextSize(2);
  spr.pushImage(8,20,40,40,bmp3_temp);spr.setCursor(60, 24);spr.print(temp.temperature,1);
  spr.loadFont(temp_30);
  spr.setCursor(115, 30);
  spr.printf("℃");
  spr.unloadFont();
  spr.pushSprite(0, 0);
}


void sayWord1()
{
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_WHITE);
  spr.setCursor(0, 0);

  spr.fillSprite(TFT_BLACK);
  spr.setTextColor(TFT_WHITE,TFT_BLACK);
  spr.setTextFont(1);
  spr.setTextSize(2);
  spr.println("Life Is A Bith");spr.println("Fuck It !");
  spr.pushSprite(0, 0);
}

void sayWord2()
{
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_WHITE);
  spr.setCursor(0, 0);

  spr.fillSprite(TFT_WHITE);
  spr.setTextColor(TFT_BLUE, TFT_WHITE);
  spr.setTextFont(2);
  spr.setTextSize(2);
  spr.println("T G Y");spr.println("Z Z W");
  spr.pushSprite(0, 0);
}


void Humidity()
{
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data

  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_WHITE);
  spr.setCursor(0, 0);

  spr.fillSprite(TFT_WHITE);
  spr.setTextColor(TFT_BLACK, TFT_WHITE);
  spr.setTextFont(2);
  spr.setTextSize(2);
  spr.pushImage(8,20,40,40,bmp6_humnew); spr.setCursor(60, 24);
  spr.print(humidity.relative_humidity,1);spr.println("%");
  spr.pushSprite(0, 0);
}

void setClock0()  //详见http://t.csdn.cn/lNVIv
{

    struct tm timeinfo;
    /*struct tm {
    int tm_sec; // 秒，取值0~59；
    int tm_min; // 分，取值0~59；
    int tm_hour; // 时，取值0~23；
    int tm_mday; // 月中的日期，取值1~31；
    int tm_mon; // 月，取值0~11；
    int tm_year; // 年，其值等于实际年份减去1900；
    int tm_wday; // 星期，取值0~6，0为周日，1为周一，依此类推；
    int tm_yday; // 年中的日期，取值0~365，0代表1月1日，1代表1月2日，依此类推；
    int tm_isdst; // 夏令时标识符，实行夏令时的时候，tm_isdst为正；不实行夏令时的进候，tm_isdst为0；不了解情况时，tm_isdst()为负
    };*/
    if (!getLocalTime(&timeinfo))
  {
  	//如果获取失败，就开启网络对时
    Serial.println("Failed to obtain time");

    configTime(8 * 3600, 0, NTP1, NTP2,NTP3);
    return;
  }

  Serial.println(&timeinfo, "%F %T %A"); // 格式化输出:2021-10-24 23:00:44 Sunday
  Serial.println(&timeinfo, "%F");
  Serial.println(&timeinfo, "%T");
  Serial.println(&timeinfo, "%A");
  Serial.print(asctime(&timeinfo));//默认打印格式：Mon Oct 25 11:13:29 2021

  // Draw a black rectangle in sprite so when we move it 1 pixel it does not leave a trail
  // on the black screen background
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_BLACK);
  spr.fillSprite(TFT_BLACK);
  spr.setTextColor(TFT_GREENYELLOW, TFT_BLACK);
  spr.setTextFont(2);
  spr.setTextSize(1);
  spr.setCursor(0, 0);           //从左上角原点显示
  spr.setCursor(40, 0);spr.println(&timeinfo, "%F");
  //spr.setCursor(30, 48);spr.print(&timeinfo, "%A");
  spr.setTextFont(2);
  spr.setTextSize(2);
  spr.setTextColor(TFT_ORANGE);
  spr.setCursor(20, 20);spr.println(&timeinfo, "%T");  //显示时分秒：hh:mm:ss
  spr.setTextSize(1);
  spr.setTextColor(TFT_GREENYELLOW);
  spr.print(&timeinfo, "%A");
  spr.print("  have a nice day");

  spr.pushSprite(0, 0);          //从左上角原点显示

}

void setClock1()
{
  struct tm timeinfo;
    if (!getLocalTime(&timeinfo))
  {
  	//如果获取失败，就开启网络对时
    Serial.println("Failed to obtain time");
    configTime(8 * 3600, 0, NTP1, NTP2,NTP3);
    return;
  }

  Serial.println(&timeinfo, "%F %T %A"); // 格式化输出:2021-10-24 23:00:44 Sunday
  Serial.println(&timeinfo, "%F");
  Serial.println(&timeinfo, "%T");
  Serial.println(&timeinfo, "%A");
  Serial.print(asctime(&timeinfo));//默认打印格式：Mon Oct 25 11:13:29 2021

  // Draw a black rectangle in sprite so when we move it 1 pixel it does not leave a trail
  // on the black screen background
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_BLACK);
  spr.fillSprite(TFT_BLACK);
  spr.setTextColor(TFT_YELLOW, TFT_BLACK);
  spr.setTextFont(2);
 // spr.setTextSize(1);
 // spr.setCursor(0, 0);           //从左上角原点显示
  //spr.setCursor(40, 0);spr.println(&timeinfo, "%F");
  spr.setTextSize(2);
  //spr.setTextFont(2);
  //spr.setCursor(14, 16);spr.println(&timeinfo, "%A");
  //spr.setTextSize(2);
  spr.setCursor(24, 24);spr.println(&timeinfo, "%T");  //显示时分秒：hh:mm:ss
  //spr.setTextSize(1);
  spr.pushSprite(0, 0);          //从左上角原点显示
}

void setClock2()
{
  // Draw a black rectangle in sprite so when we move it 1 pixel it does not leave a trail
  // on the black screen background
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_WHITE);
  spr.fillSprite(TFT_WHITE);
  spr.setTextColor(TFT_BLACK, TFT_WHITE);
  spr.setTextFont(2);
  spr.setTextSize(1);
 // spr.setCursor(0, 0);           //从左上角原点显示
  //spr.setCursor(40, 0);spr.println(&timeinfo, "%F");
  spr.pushImage(0,8,64,64, bmp8_gif[i]);//调用图片数据
  i+=1;
  if(i>4){i=0;}
  delay(100);
  //spr.pushImage(0,0,64,64,bmp2_lbili);
  spr.setCursor(80, 22);spr.println("Code by");
  spr.setCursor(90, 39);spr.println("TGY");
  spr.pushSprite(0, 0);          //从左上角原点显示
}


bool getW()
{
  String url =base+Location+UserKey;
  //添加请求头
  http.begin(url); // 准备启用连接
  int httpCode = http.GET(); // 发起GET请求
  if (httpCode > 0) // 如果状态码大于0说明请求过程无异常
  {
    if (httpCode == HTTP_CODE_OK) // 请求被服务器正常响应，等同于httpCode == 200
    {
      payload= http.getString(); // 读取服务器返回的响应正文数据
      Serial.println(payload);
    }
    else
    {
      payload ="{\"code\":\"200\",\"daily\":[{\"tempMax\":\"32\",\"tempMin\":\"25\",\"textDay\":\"晴\"},{\"tempMax\":\"31\",\"tempMin\":\"24\",\"textDay\":\"晴\"},{\"tempMax\":\"30\",\"tempMin\":\"26\",\"textDay\":\"晴\"}]}";
    }
  }
  else
  {
    Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
    payload ="{\"code\":\"200\",\"daily\":[{\"tempMax\":\"32\",\"tempMin\":\"25\",\"textDay\":\"晴\"},{\"tempMax\":\"31\",\"tempMin\":\"24\",\"textDay\":\"晴\"},{\"tempMax\":\"30\",\"tempMin\":\"26\",\"textDay\":\"晴\"}]}";

  }

  http.end(); // 结束当前连接

  const size_t capacity = 2*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(2) +
                          JSON_OBJECT_SIZE(5) + 3*JSON_OBJECT_SIZE(26) + 1320;
  DynamicJsonDocument doc(capacity);

  DeserializationError error = deserializeJson(doc,payload); //反序列化JSON数据
  //tft.println(error.c_str());
  if (!error) //检查反序列化是否成功
    {
      // 得到三天的天气json
// 得到三天的天气json
      DynamicJsonDocument todayW = doc["daily"][0];
      JsonVariant tomorrowW = doc["daily"][1];
      JsonVariant the_day_after_tomorrowW = doc["daily"][2];
      String today_status_str =todayW["textDay"];
      String tomorrow_status_str =tomorrowW["textDay"];
      String last_status_str =the_day_after_tomorrowW["textDay"];


      today_status = today_status_str;
      today_max = todayW["tempMax"];
      today_min = todayW["tempMin"];

      tomorrow_status = tomorrow_status_str;
      tomorrow_max = tomorrowW["tempMax"];
      tomorrow_min = tomorrowW["tempMin"];

      last_status = last_status_str;
      last_max = the_day_after_tomorrowW["tempMax"];
      last_min = the_day_after_tomorrowW["tempMin"];
      tft.println(today_max);
      tft.println("deserializeJson success");
      return true;
    }

}


// 显示全部天气
void show_Weather(){
  spr.drawRect(0, 0, WIDTH, HEIGHT, TFT_WHITE);
  spr.fillSprite(TFT_BLACK);//LCD清空
  spr.loadFont(font_18_weather);
  spr.setCursor(0,5);
  spr.setTextColor(TFT_BLUE,TFT_BLACK);
  spr.println("日期  状态 最高 最低");
  spr.setTextColor(TFT_ORANGE,TFT_BLACK);
  spr.setCursor(0,28);
  spr.printf("今天:%6s %d℃ %d℃\n",today_status,today_max,today_min);
  spr.printf("明天:%6s %d℃ %d℃\n",tomorrow_status,tomorrow_max,tomorrow_min);
  spr.printf("后天:%6s %d℃ %d℃\n",last_status,last_max,last_min);
  spr.unloadFont();
  spr.pushSprite(0, 0);

}

void setup()
{
  Serial.begin(115200);

  pinMode(Key0, INPUT_PULLUP);
  pinMode(Key1, INPUT_PULLUP);
  pinMode(Key2, INPUT_PULLUP);
  pinMode(Key3, INPUT_PULLUP);
  pinMode(Key4, INPUT_PULLUP);
  pinMode(REDLED,OUTPUT);

  Wire.begin(I2C_SDA,I2C_SCL);
  Serial.println("Adafruit AHT10 demo!");

 if (! aht.begin()) {
    Serial.println("Could not find AHT? Check wiring");
    while (1) delay(10);
  }
  Serial.println("AHT10 found");

  tft.init();
  tft.setRotation(3);
  tft.setTextFont(2);


  // Create a sprite of defined size
  spr.createSprite(WIDTH, HEIGHT);

  // Clear the TFT screen to black
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);
  //tft.setTextSize(1);
  tft.setCursor(25, 12);
  tft.println("Power by");
  tft.setCursor(25, 28);
  tft.setTextSize(2);
  tft.println("Arduino");
  delay(2000);

  WiFi.begin(ssid, password);
  Serial.println();
  Serial.print("WIFI Connecting");
  tft.fillScreen(TFT_BLACK);//LCD清空
  tft.setCursor(0, 0);
  tft.setTextSize(1);
  tft.print("WIFI Connecting");

  while (WiFi.status() != WL_CONNECTED)
  {
    digitalWrite(REDLED,1);
    delay(500);
    Serial.print(".");
    tft.print(".");
    digitalWrite(REDLED,0);
  }
  // 从网络时间服务器上获取并设置时间
  configTime(8 * 3600, 0, NTP1, NTP2,NTP3);
  tft.println();
  tft.println("WiFi connected!");
  if(getW()){
    tft.println("weather update!");
  };
  delay(500);
  tft.fillScreen(TFT_BLACK);//LCD清空
  tft.setCursor(4, 20);
  tft.setTextSize(2);
  tft.println("Ready!!! GO");
  tft.fillScreen(TFT_BLACK);
}

void loop()
{
    KeyScan(); // 按键扫描
    switch ( stateFlag )             // 主状态机
    {
      case 0: // 显示时间

        switch ( stateFlag2 )             // 副状态机
        {
        case 0: // 显示详细时间

          setClock0();

        break;

        case 1: // 显示时分秒

          setClock1();

        break;

        case 2: // 显示小张吃土了

          setClock2();

        break;

        case 3: // 回到首页

          setClock0();

        break;

        default:
        stateFlag = 0;
        break;
        }

      break;

      case 1: // 显示温湿度

        switch ( stateFlag2 )             // 副状态机
        {
        case 0: // 显示详细时间

          temp_hum();

        break;

        case 1: // 显示时分秒

          temp();

        break;

        case 2: // 显示小张吃土了

          Humidity();

        break;

        case 3: // 回到首页

          setClock0();

        break;
        default:
        stateFlag = 0;
        break;
        }

      break;

      case 2: // 显示CPU&GPU负载率

        switch ( stateFlag2 )             // 副状态机
        {
        case 0: // 显示详细

          //PC_infor();
          setClock2();

        break;

        case 1: // 显示GPU

          //PC_infor1();
          sayWord1();

        break;

        case 2: // 显示CPU

          //PC_infor2();
          //getW();
          show_Weather();

        break;

        case 3: // 回到首页

          setClock0();

        break;

        default:
        stateFlag = 0;
        break;
        }

      break;
      case 3: //
        setClock0();
      break;

      default:
      stateFlag = 0;
      break;
    }

}
